package com.hetang.maijiayun.adaptertools.b2cinterface.youzan.client;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

import javax.net.ssl.SSLContext;

import com.hetang.maijiayun.adaptertools.utils.JsonUtil;
import net.sf.json.JSONObject;

import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.ContentBody;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.impl.client.DefaultHttpClient;

import com.hetang.maijiayun.adaptertools.b2cinterface.youzan.request.Request;
import com.hetang.maijiayun.adaptertools.b2cinterface.youzan.request.TradesSoldGetRequest;
import com.hetang.maijiayun.adaptertools.b2cinterface.youzan.response.Response;
import com.hetang.maijiayun.adaptertools.b2cinterface.youzan.response.TradesSoldGetResponse;
import com.hetang.maijiayun.adaptertools.utils.AdapterException;
import com.hetang.maijiayun.adaptertools.utils.AdapterExceptionErrorCode;

import javax.net.ssl.SSLException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.ParseException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.conn.ssl.X509HostnameVerifier;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import java.io.UnsupportedEncodingException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Map;

public class DefaultYouzanClient {
    private static final String Version = "1.0";

    private static final String apiEntry = "https://open.koudaitong.com/api/oauthentry?";

    private static final String format = "json";

    private static final String signMethod = "md5";

    private static final String DefaultUserAgent = "KdtApiSdk Client v0.1";

    private String appId;
    private String appSecret;
    private String sessionKey;

    public DefaultYouzanClient(String appId, String appSecret, String sessionKey) {
        this.appId = appId;
        this.appSecret = appSecret;
        this.sessionKey = sessionKey;
    }

    public String get(String method, HashMap<String, String> parames) throws AdapterException {
        if (parames == null) {
            parames = new HashMap<String, String>();
        }
        parames.put("access_token", this.sessionKey);
        String responseContent = null;
        HttpClient httpClient = new DefaultHttpClient();
        // 创建TrustManager
        X509TrustManager xtm = new X509TrustManager() {
            public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            }

            public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            }

            public X509Certificate[] getAcceptedIssuers() {
                return null;
            }
        };
        // 这个好像是HOST验证
        X509HostnameVerifier hostnameVerifier = new X509HostnameVerifier() {
            public boolean verify(String arg0, SSLSession arg1) {
                return true;
            }

            public void verify(String arg0, SSLSocket arg1) throws IOException {
            }

            public void verify(String arg0, String[] arg1, String[] arg2) throws SSLException {
            }

            public void verify(String arg0, X509Certificate arg1) throws SSLException {
            }
        };
        try {
            SSLContext ctx = SSLContext.getInstance("TLS");
            // 使用TrustManager来初始化该上下文，TrustManager只是被SSL的Socket所使用
            ctx.init(null, new TrustManager[] { xtm }, null);
            // 创建SSLSocketFactory
            SSLSocketFactory socketFactory = new SSLSocketFactory(ctx);
            socketFactory.setHostnameVerifier(hostnameVerifier);
            // 通过SchemeRegistry将SSLSocketFactory注册到我们的HttpClient上
            httpClient.getConnectionManager().getSchemeRegistry().register(new Scheme("https", socketFactory, 443));
            HttpPost httpPost = new HttpPost("https://open.koudaitong.com/api/oauthentry");
            List<NameValuePair> formParams = new ArrayList<NameValuePair>(); // 构建POST请求的表单参数
            Map<String, String> mapskeys=new HashMap<String,String>();
			try {
				mapskeys = buildCompleteParams(method, parames);
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
            for (String key : mapskeys.keySet()) {
                formParams.add(new BasicNameValuePair(key, mapskeys.get(key)));
            }
            httpPost.setEntity(new UrlEncodedFormEntity(formParams, "UTF-8"));
            HttpResponse response = httpClient.execute(httpPost);
            HttpEntity entity = response.getEntity(); // 获取响应实体
            if (entity != null) {
                responseContent = EntityUtils.toString(entity, "UTF-8");
            }
        } catch (KeyManagementException e) {
        	   throw new AdapterException(
                       AdapterExceptionErrorCode.B2C_RPC_RESULT_ERROR_CODE,
                       "YouzanClient get ApiException : " +e.getMessage());
        } catch (NoSuchAlgorithmException e) {
     	   throw new AdapterException(
                   AdapterExceptionErrorCode.B2C_RPC_RESULT_ERROR_CODE,
                   "YouzanClient get ApiException : " +e.getMessage());
        } catch (UnsupportedEncodingException e) {
     	   throw new AdapterException(
                   AdapterExceptionErrorCode.B2C_RPC_RESULT_ERROR_CODE,
                   "YouzanClient get ApiException : " +e.getMessage());
        } catch (ClientProtocolException e) {
     	   throw new AdapterException(
                   AdapterExceptionErrorCode.B2C_RPC_RESULT_ERROR_CODE,
                   "YouzanClient get ApiException : " +e.getMessage());
        } catch (ParseException e) {
     	   throw new AdapterException(
                   AdapterExceptionErrorCode.B2C_RPC_RESULT_ERROR_CODE,
                   "YouzanClient get ApiException : " +e.getMessage());
        } catch (IOException e) {
     	   throw new AdapterException(
                   AdapterExceptionErrorCode.B2C_RPC_RESULT_ERROR_CODE,
                   "YouzanClient get ApiException : " +e.getMessage());
        } finally {
            // 关闭连接,释放资源
            httpClient.getConnectionManager().shutdown();
        }

        return responseContent;
    }

    public String decode(String bytes) {
        String hexString = "0123456789ABCDEF";
        ByteArrayOutputStream baos = new ByteArrayOutputStream(bytes.length() / 2);
        // 将每2位16进制整数组装成一个字节
        for (int i = 0; i < bytes.length(); i += 2)
            baos.write((hexString.indexOf(bytes.charAt(i)) << 4 | hexString.indexOf(bytes.charAt(i + 1))));
        return new String(baos.toByteArray());

    }

    public HttpResponse post(String method, HashMap<String, String> parames, List<String> filePaths, String fileKey) throws Exception {
        parames.put("access_token", this.sessionKey);
        String url = apiEntry + getParamStr(method, parames);

        HttpClient client = new DefaultHttpClient();
        HttpPost httppost = new HttpPost(url);
        httppost.addHeader("User-Agent", DefaultUserAgent);

        if (null != filePaths && filePaths.size() > 0 && null != fileKey && !"".equals(fileKey)) {
            MultipartEntity mpEntity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);
            for (int i = 0; i < filePaths.size(); i++) {
                File file = new File(filePaths.get(i));
                ContentBody cbFile = new FileBody(file);
                mpEntity.addPart(fileKey, cbFile);
            }

            httppost.setEntity(mpEntity);
        }

        HttpResponse response = client.execute(httppost);

        return response;
    }

    public String getParamStr(String method, HashMap<String, String> parames) {
        String str = "";
        try {
            str = URLEncoder.encode(buildParamStr(buildCompleteParams(method, parames)), "UTF-8").replace("%3A", ":").replace("%2F", "/")
                    .replace("%26", "&").replace("%3D", "=").replace("%3F", "?");
        } catch (Exception e) {
            e.printStackTrace();
        }

        return str;
    }

    private String buildParamStr(HashMap<String, String> param) {
    	String paramStr = "";
    	if(param!=null){
    		int i=0;
    		for(Iterator ite = param.entrySet().iterator(); ite.hasNext();){  
                Map.Entry<String,String> entry = (Map.Entry<String,String>) ite.next();  
                if (0 == i) {
                    paramStr += (entry.getKey() + "=" + entry.getValue());
                } else {
                    paramStr += ("&" + entry.getKey() + "=" +entry.getValue());
                }
                i++;
            } 
    	}
        return paramStr;
    }

    private HashMap<String, String> buildCompleteParams(String method, HashMap<String, String> parames) throws Exception {
        HashMap<String, String> commonParams = getCommonParams(method);
        if (parames != null) {
        	for(Iterator ite = parames.entrySet().iterator(); ite.hasNext();){  
                Map.Entry<String,String> entry = (Map.Entry<String,String>) ite.next();  
                if (commonParams.containsKey(entry.getKey())) {
                    throw new Exception("参数名冲突");
                }
                commonParams.put(entry.getKey(), entry.getValue());
            }  

        }

        commonParams.put(KdtApiProtocol.SIGN_KEY, KdtApiProtocol.sign(appSecret, commonParams));
        return commonParams;
    }

    private HashMap<String, String> getCommonParams(String method) {
        HashMap<String, String> parames = new HashMap<String, String>();
        parames.put(KdtApiProtocol.APP_ID_KEY, appId);
        parames.put(KdtApiProtocol.METHOD_KEY, method);
        parames.put(KdtApiProtocol.TIMESTAMP_KEY, new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
        parames.put(KdtApiProtocol.FORMAT_KEY, format);
        parames.put(KdtApiProtocol.SIGN_METHOD_KEY, signMethod);
        parames.put(KdtApiProtocol.VERSION_KEY, Version);
        return parames;
    }

    /**
     * sessionKey 非必须
     * 
     * @param <T>
     * @param request
     * @return
     * @throws YouzanException
     * @throws AdapterException
     * @throws IOException
     * @throws ClientProtocolException
     */
    public String executeGet(Request request) throws YouzanException, AdapterException {
        String url = apiEntry + getParamStr(request.getApiMethodName(), request.getParams());
        HttpClient client = new DefaultHttpClient();
        HttpGet requestget = new HttpGet(url);
        requestget.addHeader("User-Agent", DefaultUserAgent);
        HttpResponse response = null;
        try {
            response = client.execute(requestget);
        } catch (ClientProtocolException e) {
        	throw new AdapterException(
                    AdapterExceptionErrorCode.B2C_RPC_RESULT_ERROR_CODE,
                    "YouzanClient get ApiException : " +e.getMessage());
        } catch (IOException e) {
        	throw new AdapterException(
                    AdapterExceptionErrorCode.B2C_RPC_RESULT_ERROR_CODE,
                    "YouzanClient get ApiException : " +e.getMessage());
        }
        BufferedReader bufferedReader = null;
        try {
            bufferedReader = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
        } catch (IllegalStateException e) {
        	throw new AdapterException(
                    AdapterExceptionErrorCode.B2C_RPC_RESULT_ERROR_CODE,
                    "YouzanClient get ApiException : " +e.getMessage());
        } catch (IOException e) {
        	throw new AdapterException(
                    AdapterExceptionErrorCode.B2C_RPC_RESULT_ERROR_CODE,
                    "YouzanClient get ApiException : " +e.getMessage());
        }
        StringBuffer result = new StringBuffer();
        String line = "";
        try {
            while ((line = bufferedReader.readLine()) != null) {
                result.append(line);
            }
        } catch (IOException e) {
        	throw new AdapterException(
                    AdapterExceptionErrorCode.B2C_RPC_RESULT_ERROR_CODE,
                    "YouzanClient get ApiException : " +e.getMessage());
        }
        return result.toString();
    }

    public TradesSoldGetResponse execute(TradesSoldGetRequest req) throws YouzanException, AdapterException {
        String result = get(req.getApiMethodName(), req.getParams());

        JSONObject obj = JsonUtil.fromObjectNotNull(result);
        if (result.indexOf("error_response") < 0) {
            result = JsonUtil.getString(obj, "response");
        }
        return getResponse(result, TradesSoldGetResponse.class);
    }

    public <T extends Response> T getResponse(String json, Class<T> clazz) throws AdapterException {
        return JsonUtil.getBean(json, clazz);
    }

}
